ARM64逆向基础
The following article is from 游戏安全攻防 Author 游戏安全攻防
为什么要学ARM64?
android 5.0系统就开始引入Arm64-v8a,它用于支持全新的AArch64架构,这个架构也就是我们要学习的arm64汇编。目前android系统已经发展到anroid 11版本。因此现在主流的apk都是支持AArch64架构。那么我们利用IDA(反汇编工具)进行静态逆向分析so文件、或者IDA动态调试so文件,都需要和arm64汇编代码打交道,因此对于学习掌握好ARM64汇编对阅读反汇编代码能达到事半功倍的效果。
ARM64汇编由什么组成的?
• 汇编中共有34个寄存器。其中包括31个通用寄存器、SP寄存器、PC寄存器,CPSR寄存器。•31个通用寄存器中:
X0-X30:表示是64位的寄存器。
W0-W30:表示是32位的寄存器。•X31 : 也称为零寄存器(它一般用于变量的初始化),它也有两表现形式:XZR:表示是64位的零寄存器, 它在内存中是用8个字节存储。WZR:表示是32位的零寄存器,它在内存中是用4个字节存储。•SP : 保存栈指针(栈顶指针),使用SP或WSP来进行对SP寄存器的访问,也就是用于操作局部变量地址。•PC:程序计数器(PC指针寄存器),它用于指向即将要执行的下一条指令。•CPSR:状态寄存器•FP(X29):保存栈帧地址(栈底指针)•LP(X30):通常称X30为程序的链接寄存器,保存子程序结束后需要执行的下一条指令。
通用寄存器作用是什么?
•在汇编代码中使用 X0 - X30寄存器进行访问操作数据时,它就表示的是一个64位的数据。•在汇编代码中使用 W0 - W30寄存器进行访问操作数据时,它表示的是一个32位的数据。
栈寄存器是什么怎么用?
1.栈结构及作用?
栈是一种具有特殊的访问方式的存储空间,先进后出(后进先出),它是从高地址到低地址的, 栈底是高地址,栈顶是低地址。
它的主要的作用:用于存放参数和局部变量(临时变量)。
2. 栈寄存器表示指令有那些?
SP:栈顶寄存器
FP:栈底寄存器
3. 操作栈寄存器的有那些指令?
STP指令:表示入栈指令
LDP指令:表示出栈指令
入栈操作的汇编代码片段
出栈操作的汇编代码片段
状态寄存器由那些状态组成?
ARM64的汇编指令集中,有一部分指令的执行时影响状态寄存器的,比如add、sub、or汇编指令等,他们大都是运算指令(进行逻辑或算数运算)
CPSR的低8位(包括I、F、T和M[0~4])称为控制位,程序无法修改,除非CPU运行于特权模式下,程序才能修改控制位! N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。
1. N(Negative)标志
CPSR的第31位是 N,符号标志位。它记录相关指令执行后,其结果是否为负。如果为负 N = 1,如果是非负数 N = 0。
2. Z(Zero)标志
CPSR的第30位是Z,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么Z = 1;如果结果不为0,那么Z = 0。
3. C(Carry)标志
CPSR的第29位是C,进位标志位。一般情况下,进行无符号数的运算。
加法运算(add指令):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。减法运算(sub指令):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。
4. V(Overflow)溢出标志
CPSR的第28位是V,溢出标志位。在进行有符号数运算的时候,如果超过了机器所能标识的范围,称为溢出。
下面几种情况会出现溢出
正数 + 正数 为负数 溢出
负数 + 负数 为正数 溢出
正数 + 负数 不可能溢出
ARM64特有的汇编指令
•adrp指令(address page)
它是一条地址读取指令,是用于计算指定的数据地址到当前PC值的相对偏移。
下面是它具体的用法及解释
得到一个大小为4KB的页的基址,而且在该页中有全局变量g的地址;ADRP就是讲该页的基址存到寄存器X6中;
ADD指令会算出g的地址,X6+#_g@PAGEOFF,#_g@PAGEOFF是一个偏移量;这样就得到了g的地址X6;
•内存读写指令(ldr、ldur、ldp, str、stur、stp)
STR、STP、STUR为存储数据指令(注:以ST开头的表示为存储指令)
LDR、LDP、LDUR为取出数据指令(注:以LD开头的表示为取出数据)
以下是具体指令说明及汇编代码分析
STR指令:将数据从寄存器中读出来,存储到内存中。
STUR指令:将寄存器中的负数数据读取出来,存放到内存中。
STP指令:表示入栈指令。
LDR指令:将数据从内存中取出来,存放到寄存器中。
LDUR指令:将内存中负数的数据取出来,并存放到寄存器中。
LDP指令:表示出栈指令
ARM64汇编的函数有那些需要重点关注?
1.函数调用约定是什么约定?
ARM64使用的是ATPCS(ARM-Thumb Procedure Call Standard/ARM-Thumb过程调用标准)的函数调用约定。2.函数需要用到到的指令有那些?
B:无条件跳转,一般是函数内部的if、switch条件判断的跳转
Bl:带函数返回值的跳转,一般是用于调用其他的函数。RET:子程序返回指令,返回地址默认保存在X30寄存器(LR链接寄存器)
LR:保存子程序结束后需要执行的下一条指令
PC:表示当前执行的指令的地址。3.函数的参数怎么存储传递?
3.1. 通常情况下函数的参数存放在X0-X7(32位的为W0-W7)这8个寄存器,如果函数参数超过8个,那么就需要用到栈存储的方式来存储参数。
3.2. 函数参数如果少于8个参数的那么依次从左往右传参,如果多于8个的参数那么依次从右往左进行入栈的。
3.3 函数中8个参数和9个参数的具体情况(不过在开发过程中参数超过8个的情况是比较少的,因此在逆向过程中这种超过8个参数的情况也会比较少的) 3.3.1函数中有八个参数的,直接用寄存器W0-W7表示 源代码:
ARM64汇编代码:
3.3.2 函数中有九个参数的,需要用栈寄存器来传递参数 源代码:
ARM64汇编代码:
4.函数中的堆栈怎么平衡?
堆栈平衡需要被调用者进行恢复平衡。
5.函数的返回值怎么进行接收?
函数的返回值通常情况下是存放在X0寄存器里面,ret将X0寄存器的地地址值放入X30寄存器(也就是LR链接寄存器)。
大佬们留个关注再走呗,后续精彩文章不断